`timescale 1ns / 1ps
`include "define.v"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 12/13/2019 10:10:17 AM
// Design Name: 
// Module Name: sel
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module sel(
    input wire [31:0] pc,
    input wire [`aluop] alucontrolM,
    input wire [31:0] addr,
    input wire [31:0] wa,
    input wire [31:0] ra,
    output reg [31:0] wb,
    output reg [31:0] rb,
    output reg [3:0]  sel,
    output reg adelM,adesM,
    output [31:0] bad_addr,

    output [1:0] axi_size
    );
    
    assign axi_size = (`sig_sw || `sig_lw) ? 2'b10 : 
                      (`sig_sh || `sig_lh || `sig_lhu) ? 2'b01 : 2'b00;
    
    always @(*)
    begin
        adesM <= 1'b0;
        adelM <= 1'b0;
        wb <= wa;
        rb <= ra;
        sel <= 4'b0000;
        case(alucontrolM)
        // ============================== save option ==============================>>
            `sig_sw: begin
                if (addr[1:0] == 2'b00) begin
                    sel <= 4'b1111;
                    adesM <= 1'b0;
                    adelM <= 1'b0;
                    wb <= wa;
                    rb <= ra;
                end else begin
                    sel <= 4'b0000;
                    adesM <= 1'b1;
                    adelM <= 1'b0;
                    wb <= wa;
                    rb <= ra;
                end
            end
            `sig_sh: begin
                wb <= { wa[15:0], wa[15:0] };
                rb <= ra;
                adelM <= 1'b0;
                case (addr[1:0])
                    2'b10: sel <= 4'b1100;
                    2'b00: sel <= 4'b0011;
                    default: begin
                        adesM <= 1'b1;
                        sel <= 4'b0000;
                    end
                endcase
            end
            `sig_sb: begin
                wb <= { wa[7:0], wa[7:0], wa[7:0], wa[7:0] };
                adesM <= 1'b0;
                adelM <= 1'b0;
                rb <= ra;
                case (addr[1:0])
                    2'b11:sel <= 4'b1000;
					2'b10:sel <= 4'b0100;
					2'b01:sel <= 4'b0010;
					2'b00:sel <= 4'b0001;
                endcase
            end
        // ============================== save option ==============================>>
            `sig_lw: begin
                sel <= 4'b0000;
                adesM <= 1'b0;
                wb <= wa;
                rb <= ra;
                if (addr[1:0] != 2'b00) begin
                    adelM <= 1'b1;
                end else begin
                    adelM <= 1'b0;
                end
            end
            `sig_lh: begin
                adesM <= 1'b0;
                wb <= wa;

                case(addr[1:0])
                    2'b10: begin 
                        sel <= 4'b0000;
                        rb <= { {16{ra[31]}}, ra[31:16] };
                        adelM <= 1'b0;
                    end
                    2'b00: begin
                        sel <= 4'b0000;
                        rb <= { {16{ra[15]}}, ra[15:0 ] };
                        adelM <= 1'b0;

                    end
                    default: begin
                        sel <= 4'b0000;
                        rb <= ra;
                        adelM <= 1'b1;
                    end
                endcase
            end
                
                

            `sig_lhu: begin
                sel <= 4'b0000;
                wb <= wa;
                adesM <= 1'b0;

                case(addr[1:0])
                    2'b10: begin 
                        rb <= { {16{1'b0}}, ra[31:16] };
                        adelM <= 1'b0;
                    end
                    2'b00: begin 
                        rb <= { {16{1'b0}}, ra[15:0 ] };
                        adelM <= 1'b0;
                    end
                    default: begin 
                        rb <= ra;
                        adelM <= 1'b1;
                    end
                endcase
            end
                
            
             `sig_lb: begin
                sel <= 4'b0000;
                adesM <= 1'b0;
                adelM <= 1'b0;
                wb <= wa;
                case(addr[1:0])
                    2'b11: rb <= {{24{ra[31]}}, ra[31:24]};
                    2'b10: rb <= {{24{ra[23]}}, ra[23:16]};
                    2'b01: rb <= {{24{ra[15]}}, ra[15:8] };
                    2'b00: rb <= {{24{ra[7] }}, ra[7 :0] };
                endcase
             end
             `sig_lbu: begin 
                sel <= 4'b0000;
                adesM <= 1'b0;
                adelM <= 1'b0;
                wb <= wa;
                case(addr[1:0])
                    2'b11: rb <= {{24{1'b0}}, ra[31:24]};
                    2'b10: rb <= {{24{1'b0}}, ra[23:16]};
                    2'b01: rb <= {{24{1'b0}}, ra[15:8] };
                    2'b00: rb <= {{24{1'b0}}, ra[7 :0] };
                endcase
             end

             default: begin
                adesM <= 1'b0;
                adelM <= 1'b0;
                wb <= wa;
                rb <= ra;
                sel <= 4'b0000;
             end
        endcase
    end
    
    
                                    
    assign bad_addr = (adelM == 1'b1 || adesM == 1'b1) ? addr : pc; //previous: pc - 8
endmodule
